home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / umich / network / ka9q / ka9q_src.arc / SLFP.C < prev    next >
C/C++ Source or Header  |  1988-12-02  |  12KB  |  523 lines

  1. /* Send and receive IP datagrams on serial lines. Compatible with SL/FP
  2.  * as used with the Merit Network and MIT.
  3.  */
  4. #include <stdio.h>
  5. #include "global.h"
  6. #include "mbuf.h"
  7. #include "iface.h"
  8. #include "timer.h"
  9. #include "ip.h"
  10. #include "slfp.h"
  11. #ifdef UNIX    /* BSD or SYS5 */
  12. #include "unix.h"
  13. #else
  14. # ifdef ATARI_ST
  15. #  include "st.h"
  16. # else
  17. #  include "pc.h"
  18. #  include "asy.h"
  19. # endif        /* ATARI_ST */
  20. #endif        /* BSD or SYS5 */
  21. #include "trace.h"
  22.  
  23. int asy_ioctl();
  24. int slfp_send();
  25. int doslfp();
  26. int asy_output();
  27.  
  28. /* SL/FP level control structure */
  29. struct slfp slfp[ASY_MAX];
  30. char slfp_ack[ACK_LEN] = { SLFP_ACK } ;
  31. char slfp_req[REQ_LEN] = { SLFP_REQ } ;
  32. char ip_hdr[HDR_LEN] = { 2, 1, 0, 0 } ;    /* IP Packet Header */
  33. char ar_hdr[HDR_LEN] = { 2, 3, 0, 0 } ;    /* "Addr Req" Packet Header */
  34. struct interface asy_interface =    /* Fake interface for "dump" proc */
  35.     { NULLIF, "asy" } ;        /* Name of "asy" interface */
  36.  
  37. /* Routine to Initialize the Async line for SL/FP processing.
  38.  * Mostly involves requesting the IP Address for this host.
  39.  */
  40. int
  41. slfp_init(interface,pip_addr,modem_cmd)
  42. struct interface *interface ;
  43. int32 *pip_addr ;        /* pointer to host ip address */
  44. char *modem_cmd ;        /* optional command to Modem */
  45. {
  46.     register struct slfp *sp;
  47.     register struct timer *ar ;
  48.     char *modem_line ;
  49.     int i ;
  50.  
  51.     sp = &slfp[interface->dev];
  52.     ar = &sp->ar_timer ;
  53.     sp->ar_pending = 1 ;
  54.     slfp[interface->dev].req_pending = 0 ;
  55.  
  56.     /* If a Modem Command is present, send it and wait for Connection */
  57.     if (modem_cmd != NULLCHAR) {
  58.     char c; c='\r';
  59.     modem_line = (char *)malloc(strlen(modem_cmd)+2) ;
  60.     if (modem_line == NULLCHAR)
  61.         return -1 ;
  62.     strcpy(modem_line, modem_cmd);
  63.     strcat(modem_line, "\r") ;
  64.     asy_output(interface->dev,&c,1);    /* Wake up modem */
  65.     set_timer(ar,500);
  66.     start_timer(ar);
  67.     while(ar->state == TIMER_RUN)
  68.         keep_things_going();
  69.     asy_output(interface->dev,modem_line,strlen(modem_line));
  70.     set_timer(ar, 30000) ;    /* Wait upto 30 seconds for Connection */
  71.     } else
  72.     set_timer(ar, 500) ; /* Wait half a second before sending REQ's */
  73.  
  74.     /* Request an IP Address upto 4 times (every 24 seconds) before giving up */
  75.     for (i=0; i<4; i++) {
  76.     start_timer(ar) ;
  77.     while (sp->ar_pending && (ar->state == TIMER_RUN)) {
  78.         keep_things_going() ;    /* Can't return until timeout or addr */
  79.         if(kbread()==(-2))        /* Hit the Escape key */
  80.         return(-1);
  81.     }
  82.     if (!sp->ar_pending) {
  83.         if (modem_cmd != NULLCHAR)
  84.         free(modem_line) ;
  85.         return 0 ;
  86.     }
  87.     slfp_send(NULLBUF, interface, 0L, 0, 0, 0, 0) ;
  88.     set_timer(ar, 24000) ;    /* Wait upto 24 seconds for IP Addr */
  89.     }
  90.  
  91.     if (modem_cmd != NULLCHAR)
  92.     free(modem_line) ;
  93.     sp->ar_pending = 0 ;
  94.     return -1 ;
  95. }
  96.  
  97. /* Send routine for point-to-point slfp
  98.  * This is a trivial function since slfp_encode adds the link-level header
  99.  */
  100. int
  101. slfp_send(bp,interface,gateway,precedence,delay,throughput,reliability)
  102. struct mbuf *bp;        /* Buffer to send */
  103. struct interface *interface;    /* Pointer to interface control block */
  104. int32 gateway;
  105. char precedence;
  106. char delay;
  107. char throughput;
  108. char reliability;
  109. {
  110.     if(interface == NULLIF){
  111.         free_p(bp);
  112.         return;
  113.     }
  114.     dump(interface,IF_TRACE_OUT,TRACE_IP,bp);
  115.     (*interface->raw)(interface,bp);
  116. }
  117. /* Send a raw slfp frame -- also trivial */
  118. slfp_raw(interface,bp)
  119. struct interface *interface;
  120. struct mbuf *bp;
  121. {
  122.     /* Make "asy" interface a shadow of the SLFP interface */
  123.     asy_interface.trace = interface->trace ;
  124.  
  125.     /* Queue a frame on the slfp output queue and start transmitter */
  126.     slfpq(interface->dev,bp);
  127. }
  128. /* Encode a raw packet in slfp framing, put on link output queue, and kick
  129.  * transmitter
  130.  */
  131. static
  132. slfpq(dev,bp)
  133. int16 dev;        /* Serial line number */
  134. struct mbuf *bp;    /* Buffer to be sent */
  135. {
  136.     register struct slfp *sp;
  137.     struct mbuf *slfp_encode();
  138.  
  139.     if((bp = slfp_encode(dev,bp)) == NULLBUF)
  140.         return;    
  141.  
  142.     sp = &slfp[dev];
  143.     enqueue(&sp->sndq,bp);
  144.     dump(&asy_interface,IF_TRACE_OUT,TRACE_SLFP,bp);
  145.     sp->sndcnt++;
  146.     if(sp->tbp == NULLBUF)
  147.         slfp_asy_start(dev);
  148. }
  149.  
  150. /* Handle REQ-ACK Timer expiration
  151.  */
  152. void
  153. slfp_req_notify(dev)
  154. int16 dev;
  155. {
  156.     register struct slfp *sp;
  157.     register struct timer *rt ;        /* Timer for REQ-ACK negotiation */
  158.     struct mbuf *bp ;
  159.  
  160.     sp = &slfp[dev];
  161.     rt = &(sp->req_timer) ;
  162.     if (sp->reqcnt++ >= 10) {
  163.     sp->tbp = NULLBUF ;
  164.     sp->req_pending = 0 ;
  165.     bp = dequeue(&sp->sndq);
  166.     sp->sndcnt--;
  167.     free_p(bp) ;
  168.     }
  169.     else {
  170.     set_timer(rt,2000) ;        /* 2-Second Timeout for ACK */
  171.     start_timer(rt) ;
  172.     asy_output(dev, slfp_req, REQ_LEN) ;
  173.     }
  174. }
  175.  
  176. /* Start output, if possible, on asynch device dev */
  177. static
  178. slfp_asy_start(dev)
  179. int16 dev;
  180. {
  181.     register struct slfp *sp;
  182.     register struct timer *rt ;    /* Timer for REQ-ACK negotiation */
  183.     struct mbuf *bp ;
  184.  
  185.     if(!stxrdy(dev))
  186.         return;        /* Transmitter not ready */
  187.  
  188.     sp = &slfp[dev];
  189.     bp = sp->tbp ;
  190.     if(bp != NULLBUF){
  191.         /* transmission just completed */
  192.         free_p(bp) ;
  193.         sp->tbp = NULLBUF;
  194.     }
  195.     if(sp->sndq == NULLBUF)
  196.         return;    /* No work */
  197.  
  198.     rt = &(sp->req_timer) ;
  199.     if (sp->req_pending)
  200.         return ;
  201.     sp->reqcnt = 0 ;
  202.     sp->req_pending = 1 ;
  203.     rt->func = slfp_req_notify ;
  204.     rt->arg = (char *)dev ;
  205.     set_timer(rt,2000) ;        /* 2-Second Timeout for ACK */
  206.     start_timer(rt) ;
  207.     asy_output(dev, slfp_req, REQ_LEN) ;
  208. }
  209. /* Encode a packet in SL/FP format */
  210. static
  211. struct mbuf *
  212. slfp_encode(dev,bp)
  213. int16 dev;        /* Serial line number */
  214. struct mbuf *bp;
  215. {
  216.     struct mbuf *lbp;    /* Mbuf containing line-ready packet */
  217.     register char *cp;
  218.     char c;
  219.  
  220.     /* Allocate output mbuf that's twice as long as the packet.
  221.      * This is a worst-case guess (consider a packet full of SLFP_ENDs!)
  222.      */
  223.     lbp = alloc_mbuf(HDR_LEN + 2*len_mbuf(bp) + 2);
  224.     if(lbp == NULLBUF){
  225.         /* No space; drop */
  226.         free_p(bp);
  227.         return NULLBUF;
  228.     }
  229.     cp = lbp->data;
  230.  
  231.     /* Prefix packet with the Correct Link-Level Header */
  232.     if (slfp[dev].ar_pending)
  233.         memcpy(cp, ar_hdr, HDR_LEN) ;
  234.     else
  235.         memcpy(cp, ip_hdr, HDR_LEN) ;
  236.     cp += HDR_LEN ;
  237.  
  238.     /* Copy input to output, escaping special characters */
  239.     while(pullup(&bp,&c,1) == 1){
  240.         switch(c & 0xff){
  241.         case SLFP_ESC:
  242.             *cp++ = SLFP_ESC;
  243.             *cp++ = SLFP_ESC - SLFP_ESC;
  244.             break;
  245.         case SLFP_END:
  246.             *cp++ = SLFP_ESC;
  247.             *cp++ = SLFP_END - SLFP_ESC;
  248.             break;
  249.         case SLFP_ACK:
  250.             *cp++ = SLFP_ESC;
  251.             *cp++ = SLFP_ACK - SLFP_ESC;
  252.             break;
  253.         case SLFP_REQ:
  254.             *cp++ = SLFP_ESC;
  255.             *cp++ = SLFP_REQ - SLFP_ESC;
  256.             break;
  257.         default:
  258.             *cp++ = c;
  259.         }
  260.     }
  261.     *cp++ = SLFP_END;
  262.     lbp->cnt = cp - lbp->data;
  263.     return lbp;
  264. }
  265.  
  266. #ifdef    MSDOS
  267. /* Invoked when SLFP_REQ is received during xmit of outgoing packet.
  268.  * This allows immediate reception of packet from SCP, rather than
  269.  * forcing it to buffer it until we finish sending the outgoing packet
  270.  */
  271. static
  272. unsigned
  273. slfp_urgent(dev)
  274. int16 dev;    /* SL/FP unit number */
  275. {
  276.     register struct dma *dp ;
  277.  
  278.     dp = &asy[dev].dma ;
  279.     if (dp->last_octet == SLFP_ESC)
  280.     return 256 ;
  281.     else {
  282.     asy[dev].urgent = NULLCHAR ;
  283.     return SLFP_ACK ;
  284.     }
  285. }
  286. #endif
  287.  
  288. void
  289. hndl_rcvd_req(dev, sp)
  290. int16 dev;    /* SL/FP unit number */
  291. register struct slfp *sp;
  292. {
  293.     char i_state ;
  294.  
  295.     if (sp->reqd) { /* REQ before rcv'g END of last Packet! */
  296.     sp->missed_ends++ ;
  297.     free_p(sp->rbp);    /* throw away current packet */
  298.     sp->rbp = NULLBUF;
  299.     sp->rcnt = 0;
  300.     }
  301.  
  302.     sp->reqd = 1 ;
  303.     i_state = disable() ;
  304. #ifdef    MSDOS
  305.     if (asy[dev].dma.flags)
  306.     asy[dev].urgent = slfp_urgent ;
  307.     else
  308. #endif
  309.     asy_output(dev, slfp_ack, ACK_LEN) ;
  310.     restore(i_state) ;
  311. }
  312.  
  313. void
  314. hndl_rcvd_ack(dev, sp)
  315. int16 dev;    /* SL/FP unit number */
  316. register struct slfp *sp;
  317. {
  318.     char i_state ;
  319.  
  320.     i_state = disable() ;
  321.     if (sp->req_pending == 0) {
  322.         sp->false_acks++ ;
  323.         restore(i_state) ;
  324.         return ;
  325.     }
  326.     sp->req_pending = 0 ;
  327.     stop_timer(&(sp->req_timer)) ;
  328.     restore(i_state) ;
  329.     sp->tbp = dequeue(&sp->sndq);
  330.     sp->sndcnt--;
  331.     asy_output(dev,sp->tbp->data,sp->tbp->cnt);
  332. }
  333.  
  334. /* Process incoming bytes in